package com.ld.shieldsb.es.model.search;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import com.ld.shieldsb.common.core.reflect.FunctionUtil.Property;
import com.ld.shieldsb.dao.model.QueryManager;
import com.ld.shieldsb.es.model.search.Condition.LinkType;

import lombok.Data;

/**
 * 多查询条件
 * 
 * @author <a href="mailto:donggongai@126.com" target="_blank">吕凯</a>
 * @date 2020年6月2日 下午6:12:35
 *
 */
@Data
public class MultiCondition {
    public List<Condition> conditions = new ArrayList<>(); // 条件

    public LinkType type = LinkType.AND;

    // ============================= eq类型 =======================================
    // andEq
    public MultiCondition andEq(String fieldName, Object value) {
        andEq(fieldName, value, null);
        return this;
    }

    public <T> MultiCondition andEq(Property<T, ?> property, Object value) {
        return andEq(QueryManager.getFunctionName(property), value);
    }

    public MultiCondition andEq(String fieldName, Object value, Float boost) {
        addEq(fieldName, value, LinkType.AND, boost);
        return this;
    }

    public <T> MultiCondition andEq(Property<T, ?> property, Object value, Float boost) {
        return andEq(QueryManager.getFunctionName(property), value, boost);
    }

    // orEQ
    public MultiCondition orEq(String fieldName, Object value) {
        orEq(fieldName, value, null);
        return this;
    }

    public <T> MultiCondition orEq(Property<T, ?> property, Object value) {
        return orEq(QueryManager.getFunctionName(property), value);
    }

    public MultiCondition orEq(String fieldName, Object value, Float boost) {
        addEq(fieldName, value, LinkType.OR, boost);
        return this;
    }

    public <T> MultiCondition orEq(Property<T, ?> property, Object value, Float boost) {
        return orEq(QueryManager.getFunctionName(property), value, boost);
    }

    /**
     * 添加等于条件
     * 
     * @Title addEq
     * @author 吕凯
     * @date 2020年8月18日 下午3:37:15
     * @param fieldName
     * @param value
     * @param linkType
     *            void
     */
    private void addEq(String fieldName, Object value, LinkType linkType, Float boost) {
        Condition cnd = new Condition(fieldName, Condition.Type.EQUAL, value);
        if (linkType != null) {
            cnd.setLinkType(linkType);
        }
        cnd.setBoost(boost);
        getConditions().add(cnd);
    }
    // ============================= 分词类型 =======================================

    // 添加分词
    public MultiCondition andAnalysis(String fieldName, String value, String otherFieldNames) {
        addAnalysis(fieldName, value, otherFieldNames, LinkType.AND, null);
        return this;
    }

    public MultiCondition andAnalysis(String fieldName, String value) {
        andAnalysis(fieldName, value, (String) null);
        return this;
    }

    /**
     * 分词查询多字段
     * 
     * @Title andAnalysis
     * @author 吕凯
     * @date 2020年8月18日 下午3:26:43
     * @param <T>
     * @param property
     * @param value
     * @param otherFieldNames
     *            其他查询字段，用逗号分隔
     * @return MultiCondition
     */
    public <T> MultiCondition andAnalysis(Property<T, ?> property, String value, String otherFieldNames) {
        return andAnalysis(QueryManager.getFunctionName(property), value, otherFieldNames);
    }

    public <T> MultiCondition andAnalysis(Property<T, ?> property, String value) {
        return andAnalysis(property, value, (String) null);
    }

    public MultiCondition andAnalysis(String fieldName, String value, String otherFieldNames, Float boost) {
        addAnalysis(fieldName, value, otherFieldNames, LinkType.AND, boost);
        return this;
    }

    public MultiCondition andAnalysis(String fieldName, String value, Float boost) {
        andAnalysis(fieldName, value, null, boost);
        return this;
    }

    /**
     * 分词查询多字段
     * 
     * @Title andAnalysis
     * @author 吕凯
     * @date 2020年8月18日 下午3:26:43
     * @param <T>
     * @param property
     * @param value
     * @param otherFieldNames
     *            其他查询字段，用逗号分隔
     * @return MultiCondition
     */
    public <T> MultiCondition andAnalysis(Property<T, ?> property, String value, String otherFieldNames, Float boost) {
        return andAnalysis(QueryManager.getFunctionName(property), value, otherFieldNames, boost);
    }

    public <T> MultiCondition andAnalysis(Property<T, ?> property, String value, Float boost) {
        return andAnalysis(QueryManager.getFunctionName(property), value, null, boost);
    }

    // or
    public MultiCondition orAnalysis(String fieldName, String value, String otherFieldNames) {
        addAnalysis(fieldName, value, otherFieldNames, LinkType.OR, null);
        return this;
    }

    public MultiCondition orAnalysis(String fieldName, String value) {
        return orAnalysis(fieldName, value, (String) null);
    }

    /**
     * 分词查询多字段
     * 
     * @Title orAnalysis
     * @author 吕凯
     * @date 2020年8月18日 下午3:26:43
     * @param <T>
     * @param property
     * @param value
     * @param otherFieldNames
     *            其他查询字段，用逗号分隔
     * @return MultiCondition
     */
    public <T> MultiCondition orAnalysis(Property<T, ?> property, String value, String otherFieldNames) {
        return orAnalysis(QueryManager.getFunctionName(property), value, otherFieldNames);
    }

    public <T> MultiCondition orAnalysis(Property<T, ?> property, String value) {
        return orAnalysis(QueryManager.getFunctionName(property), value, (String) null);
    }

    public MultiCondition orAnalysis(String fieldName, String value, String otherFieldNames, Float boost) {
        addAnalysis(fieldName, value, otherFieldNames, LinkType.OR, boost);
        return this;
    }

    public MultiCondition orAnalysis(String fieldName, String value, Float boost) {
        return orAnalysis(fieldName, value, null, boost);
    }

    /**
     * 分词查询多字段
     * 
     * @Title orAnalysis
     * @author 吕凯
     * @date 2020年8月18日 下午3:26:43
     * @param <T>
     * @param property
     * @param value
     * @param otherFieldNames
     *            其他查询字段，用逗号分隔
     * @return MultiCondition
     */
    public <T> MultiCondition orAnalysis(Property<T, ?> property, String value, String otherFieldNames, Float boost) {
        return orAnalysis(QueryManager.getFunctionName(property), value, otherFieldNames, boost);
    }

    public <T> MultiCondition orAnalysis(Property<T, ?> property, String value, Float boost) {
        return orAnalysis(QueryManager.getFunctionName(property), value, null, boost);
    }

    /**
     * 添加分词条件
     * 
     * @Title addAnalysis
     * @author 吕凯
     * @date 2020年8月18日 下午3:36:40
     * @param fieldName
     * @param value
     * @param otherFieldNames
     * @param linkType
     *            void
     */
    private void addAnalysis(String fieldName, Object value, String otherFieldNames, LinkType linkType, Float boost) {
        Condition cnd = new Condition(fieldName, Condition.Type.ANALYSIS, value, otherFieldNames);
        if (linkType != null) {
            cnd.setLinkType(linkType);
        }
        cnd.setBoost(boost);
        getConditions().add(cnd);
    }

    // ======================== unEQ类型 =============================
    public MultiCondition andUnEq(String fieldName, Object value, Float boost) {
        Condition cnd = new Condition(fieldName, Condition.Type.NOT_EQUAL, value);
        cnd.setBoost(boost);
        getConditions().add(cnd);
        return this;
    }

    public <T> MultiCondition andUnEq(Property<T, ?> property, Object value, Float boost) {
        return andUnEq(QueryManager.getFunctionName(property), value);
    }

    public MultiCondition andUnEq(String fieldName, Object value) {
        return andUnEq(fieldName, value, null);
    }

    public <T> MultiCondition andUnEq(Property<T, ?> property, Object value) {
        return andUnEq(QueryManager.getFunctionName(property), value);
    }

    // 大于
    public MultiCondition andGt(String fieldName, Object value) {
        Condition cnd = new Condition(fieldName, Condition.Type.GT, value);
        getConditions().add(cnd);
        return this;
    }

    public <T> MultiCondition andGt(Property<T, ?> property, Object value) {
        return andGt(QueryManager.getFunctionName(property), value);
    }

    public MultiCondition andGe(String fieldName, Object value) {
        Condition cnd = new Condition(fieldName, Condition.Type.GE, value);
        getConditions().add(cnd);
        return this;
    }

    public <T> MultiCondition andGe(Property<T, ?> property, Object value) {
        return andGe(QueryManager.getFunctionName(property), value);
    }

    // 小于
    public MultiCondition andLt(String fieldName, Object value) {
        Condition cnd = new Condition(fieldName, Condition.Type.LT, value);
        getConditions().add(cnd);
        return this;
    }

    public <T> MultiCondition andLt(Property<T, ?> property, Object value) {
        return andLt(QueryManager.getFunctionName(property), value);
    }

    public MultiCondition andLe(String fieldName, Object value) {
        Condition cnd = new Condition(fieldName, Condition.Type.LE, value);
        getConditions().add(cnd);
        return this;
    }

    public <T> MultiCondition andLe(Property<T, ?> property, Object value) {
        return andLe(QueryManager.getFunctionName(property), value);
    }

    public MultiCondition andLeftLike(String fieldName, String value) {
        Condition cnd = new Condition(fieldName, Condition.Type.LIKE_LEFT, value + "*");
        getConditions().add(cnd);
        return this;
    }

    public <T> MultiCondition andLeftLike(Property<T, ?> property, String value) {
        return andLeftLike(QueryManager.getFunctionName(property), value);
    }

    public MultiCondition andRightLike(String fieldName, String value) {
        Condition cnd = new Condition(fieldName, Condition.Type.LIKE_RIGHT, "*" + value);
        getConditions().add(cnd);
        return this;
    }

    public <T> MultiCondition andRightLike(Property<T, ?> property, String value) {
        return andRightLike(QueryManager.getFunctionName(property), value);
    }

    public MultiCondition andLike(String fieldName, String value) {
        Condition cnd = new Condition(fieldName, Condition.Type.LIKE, "*" + value + "*");
        getConditions().add(cnd);
        return this;
    }

    public <T> MultiCondition andLike(Property<T, ?> property, String value) {
        return andLike(QueryManager.getFunctionName(property), value);
    }

    // 范围
    public MultiCondition andRange(String fieldName, Object value1, Object value2) {
        return andRange(fieldName, value1, value2, null);
    }

    public <T> MultiCondition andRange(Property<T, ?> property, Object value1, Object value2) {
        return andRange(QueryManager.getFunctionName(property), value1, value2);
    }

    public MultiCondition andRange(String fieldName, Object value1, Object value2, Float boost) {
        List<Object> list = new ArrayList<>();
        list.add(value1);
        list.add(value2);
        Condition cnd = new Condition(fieldName, Condition.Type.RANGE, list);
        cnd.setBoost(boost);
        getConditions().add(cnd);
        return this;
    }

    public <T> MultiCondition andRange(Property<T, ?> property, Object value1, Object value2, Float boost) {
        return andRange(QueryManager.getFunctionName(property), value1, value2, boost);
    }

    // set类型
    public MultiCondition andInSet(String fieldName, Object[] values) {
        addInSet(fieldName, values, LinkType.AND);
        return this;
    }

    public <T> MultiCondition andInSet(Property<T, ?> property, Object[] values) {
        return andInSet(QueryManager.getFunctionName(property), values);
    }

    public <T> MultiCondition andInSet(Property<T, ?> property, Set<?> values) {
        return andInSet(QueryManager.getFunctionName(property), values);
    }

    public MultiCondition andInSet(String fieldName, Set<?> values) {
        return andInSet(fieldName, values.toArray());
    }

    public MultiCondition orInSet(String fieldName, Object[] values) {
        addInSet(fieldName, values, LinkType.OR);
        return this;
    }

    public <T> MultiCondition orInSet(Property<T, ?> property, Object[] values) {
        return orInSet(QueryManager.getFunctionName(property), values);
    }

    public <T> MultiCondition orInSet(Property<T, ?> property, Set<?> values) {
        return orInSet(QueryManager.getFunctionName(property), values);
    }

    public MultiCondition orInSet(String fieldName, Set<?> values) {
        return orInSet(fieldName, values.toArray());
    }

    /**
     * 添加set条件
     * 
     * @Title addInSet
     * @author 吕凯
     * @date 2020年8月18日 下午3:36:21
     * @param fieldName
     * @param values
     * @param linkType
     *            void
     */
    private void addInSet(String fieldName, Object[] values, LinkType linkType) {
        Condition cnd = new Condition(fieldName, Condition.Type.IN_SET, values);
        if (linkType != null) {
            cnd.setLinkType(linkType);
        }
        getConditions().add(cnd);
    }

}
